/*!
 * nodeclub - app.js
 */

/**
 * Module dependencies.
 */

var appInit = require('./appinit.js');
var config = require('./config');
var path = require('path');
var express = require('express');
var _ = require('lodash');
var Loader = require('loader');
var session = require('express-session');
var passport = require('passport');
// start db
var mdb = require('./middlewares/database');
// wire models
require('./models');
// start eventq as event subscriptions
require('./middlewares/eventq');
// start worker to generate scheduling jobs
require('./middlewares/scheduling');
// add utils to Date object https://www.npmjs.com/package/date-utils
require('date-utils');
var webRouter = require('./web_router');
var apiRouterV1 = require('./api_router_v1');
var auth = require('./middlewares/auth');
var MongoStore = require('connect-mongo')(session);
var csurf = require('csurf');
var compress = require('compression');
var bodyParser = require('body-parser');
var busboy = require('connect-busboy');
var errorhandler = require('errorhandler');
var cors = require('cors');
var gfs = require('gridfs-stream');
// add utils to Date object https://www.npmjs.com/package/date-utils
require('date-utils');
var u = require('util');
var common = require('./common');
var requestUtil = require('./common/requestUtils');
var logger = require('./common/loggerUtil').getLogger('app');


// Log an event that we have started.
appInit.appPromise.onResolve(function(err) {
    if (!err) {
        console.log('+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +');
        console.log(common.copyRightStringQualify(u.format('+ Arrking Asset Management ® is listening on port %d in %s mode', config.port, app.settings.env)));
        console.log(common.copyRightStringQualify(u.format('+ Service URL http://%s:%d', config.hostname, config.port)));
        console.log('+ Arrking Asset Management is an Enterprise Asset Management (EAM) software         +');
        console.log('+ solution product produced by Beijing Arrking Tech Co., Ltd.                       +');
        console.log('+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +');
    } else {
        logger.error(err);
    }
});

// 静态文件目录
var staticDir = path.join(__dirname, 'public');

// assets
var assets = {};
if (config.mini_assets) {
    try {
        assets = require('./assets.json');
    } catch (e) {
        console.log('You must execute `make build` before start app when mini_assets is true.');
        throw e;
    }
}

var urlinfo = require('url').parse(config.host);
config.hostname = urlinfo.hostname || config.host;

var app = express();

// configuration in all env
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'html');
app.engine('html', require('ejs-mate'));
app.locals._layoutFile = 'layout.html';

app.use(require('response-time')());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
    extended: true
}));
app.use(require('method-override')());
app.use(require('cookie-parser')(config.session_secret));
app.use(compress());
app.use(session({
    secret: config.session_secret,
    store: new MongoStore({
        url: config.db
    }),
    resave: true,
    saveUninitialized: true,
}));

app.use(passport.initialize());

// custom middleware
app.use(auth.authUser);
app.use(auth.blockUser());

app.use(Loader.less(__dirname));
app.use('/public', express.static(staticDir));

if (!config.debug) {
    app.use(function(req, res, next) {
        if (req.path.indexOf('/api') === -1) {
            csurf()(req, res, next);
            return;
        }
        next();
    });
    app.set('view cache', true);
}

// for debug
// app.get('/err', function (req, res, next) {
//   next(new Error('haha'))
// });

// set static, dynamic helpers
_.extend(app.locals, {
    config: config,
    Loader: Loader,
    assets: assets
});

_.extend(app.locals, require('./common/render_helper'));
app.use(function(req, res, next) {
    res.locals.csrf = req.csrfToken ? req.csrfToken() : '';
    next();
});

// github oauth
passport.serializeUser(function(user, done) {
    done(null, user);
});
passport.deserializeUser(function(user, done) {
    done(null, user);
});

app.use(busboy({
    limits: {
        fileSize: 10 * 1024 * 1024 // 10MB
    }
}));

var serverDown = false;
process.on('uncaughtException', function(err) {
    serverDown = true;
    logger.error('Unexpected exception: ' + err);
    logger.error('Unexpected exception stack: ' + err.stack);
});

app.use(function(req, res, next) {
    if (serverDown)
        requestUtil.errCodeResponse('Oh no!  The server is down.  Try again later.', requestUtil.httpcode.SERVICE_UNAVAILABLE, res);
    else if (mdb.databaseStatus === true)
        return next();
    else if (!mdb.databaseStatus)
        requestUtil.errCodeResponse('Server initializing', requestUtil.httpcode.SERVICE_UNAVAILABLE, res);
    else
        requestUtil.errResponse(mdb.databaseStatus, res); // It gets here for anonymous before db dropped.
});

// routes
app.use('/', webRouter);
app.use('/api/v1', cors(), apiRouterV1);

// error handler
if (config.debug) {
    app.use(errorhandler());
} else {
    app.use(function(err, req, res, next) {
        return res.status(500).send('500 status');
    });
}

app.listen(config.port, function() {
    appInit.resolve();
});

module.exports = app;
